﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Jb.Common.Extensions;
using Jb.Domain;
using Jb.Web.ViewModels;
using Jb.Web.Utility;
using AutoMapper;
using System.Data;
using Jb.Web.ViewModels.UtilityModels;
using Jb.Search;
using System.IO;


namespace Jb.Web.Areas.JobSeeker.Controllers
{
    [Authorize(Roles = "Job Seeker,Admin")]
    public class ResumeController : BaseController
    {
		private JbEntities _Context = new JbEntities();
        
		#region Constructors
		public ResumeController()
		{
		}

		public ResumeController(UserViewModel currentUser)
			: base(currentUser)
        {
        }
		#endregion Constructors

		#region Action Methods

        /// <summary>
        /// Shows the list of Resumes
        /// </summary>
        /// <returns></returns>
        public ActionResult Index()
        {
            return View("list", BuildResumeListConfig());
        }
        public ActionResult List()
        {
            return View(BuildResumeListConfig());
        }
        
		/// <summary>
        /// Gets a Resume from Database to edit
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
		public ActionResult Edit(int id = 0, String isSaved = null, String indexResume = null)
        {
            Resume entity = null;
            if (id == 0)
            {
                entity = new Resume();
                entity.JobSeekerID = LoggedInUser.JobSeekerID;
                Resume existingResume = _Context.Resumes.FirstOrDefault(P => P.JobSeekerID == LoggedInUser.JobSeekerID);
                if (existingResume == null)
                    entity.IsDefault = true;
            }
            else
            {
                entity = _Context.Resumes.FirstOrDefault(P => P.ID == id);
                if (entity != null && entity.JobSeekerID != LoggedInUser.JobSeekerID)
                    return base.RedirectToAccessDenied();
            }
            ResumeViewModel viewModel = Mapper.Map<Resume, ResumeViewModel>(entity);
            if (isSaved.ToBoolean())
                ViewData[AppConstants.ViewDataKeys.SAVED] = true;

            if (indexResume.ToBoolean())
                ViewData[AppConstants.ViewDataKeys.NEW_ID] = entity.ID;

            return View(viewModel);
        }

		/// <summary>
        /// Saves Resume Information into the Database
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
		[HttpPost]
		public ActionResult Edit(HttpPostedFileBase resumeFile, ResumeViewModel viewModel)
        {
			if (!ModelState.IsValid)
                return View(viewModel);

            if (viewModel.JobSeekerID != LoggedInUser.JobSeekerID) ///Probable hacking attempt
                return base.RedirectToAccessDenied();

            bool indexResume = false;
            if (resumeFile != null && resumeFile.ContentLength > 0)
            {
                ITextExtractor extractor = TextExtractorFactory.GetExtractor(resumeFile.FileName);
                if (extractor == null)
                    ModelState.AddModelError("FileName", String.Format("Sorry! We do not support *{0} type of file for resume.", System.IO.Path.GetExtension(resumeFile.FileName)));

                if (resumeFile.ContentLength > (1048576 * SiteConfigReader.MaxResumeFileSize))
                    ModelState.AddModelError("FileName", String.Format("Sorry! Your resume exceeds the maximum resume file upload limit of {0} MB. Please shorten your resume to reduce the file size.", SiteConfigReader.MaxResumeFileSize.ToString()));
                
                if(!ModelState.IsValid)
                    return View(viewModel);

                if(ModelState.IsValid && viewModel.IsDefault.ToBoolean())
                    indexResume = true;
            }

			Resume entity = null;
            if (viewModel.ID == 0)
            {
                entity = new Resume();
                _Context.AddToResumes(entity);
                if (viewModel.IsDefault.ToBoolean())
                    indexResume = true;
            }
            else
            {
                entity = _Context.Resumes.FirstOrDefault(P => P.ID == viewModel.ID);
                if ((viewModel.IsDefault.ToBoolean() != entity.IsDefault) && viewModel.IsDefault.ToBoolean())
                    indexResume = true;
            }            

            entity = Mapper.Map<ResumeViewModel, Resume>(viewModel, entity);
            entity.ModifiedOn = DateTime.Now;
            entity.JobSeekerID = LoggedInUser.JobSeekerID;
            SaveResume(resumeFile, entity);
            _Context.SaveChanges();
            
            if (viewModel.ID == 0)            
                JbEvents.ResumeAdded(entity, _Context);

            ViewData[AppConstants.ViewDataKeys.SAVED] = true;
            viewModel.FileName = entity.FileName;
            if (indexResume)
            {
                RemoveResumeFromDefault(entity.ID, LoggedInUser.JobSeekerID);
                ViewData[AppConstants.ViewDataKeys.NEW_ID] = entity.ID;
            }
            if(indexResume)
                return RedirectToAction(String.Format("Edit/{0}", entity.ID), new { IsSaved = "true", IndexResume = "true" });
            else
                return RedirectToAction(String.Format("Edit/{0}", entity.ID), new { IsSaved = "true" });
            //return View(viewModel);
        }

        /// <summary>
        /// Tries to delete a resume
        /// User has the right to delete a resume even if they have refence in other tables.
        /// In that case the references (JobApplication, FavoriteResume) will be deleted also.
        /// </summary>
        /// <param name="resumeID"></param>
        /// <returns>Different Status messages. And they are
        /// -1  -> Could not found resume for delete
        /// -2  -> You have applied for a job with this resume.
        /// -3  -> This is a favorite resume
        /// -4  -> Permission Denied
        /// +1  -> Successfully deleted resume
        /// +2  -> Forcefully Deleted Resume
        /// </returns>
        public int DeleteResume(int resumeID, String forceDelete)
        {
            bool isForceDelete = forceDelete.ToBoolean();
            
            Resume resume = _Context.Resumes.FirstOrDefault(P => P.ID == resumeID);
            if (resume == null)
                return -1;
            if (resume.JobSeekerID != LoggedInUser.JobSeekerID)
                return -4;
            if (isForceDelete)
            {
                ///Delete Short listed Resumes
                foreach (var jobApplication in resume.JobApplications.ToList())
                {
                    _Context.DeleteObject(jobApplication);
                }
                ///Delete Short listed Resumes
                foreach (var favoriteResume in resume.FavoriteResumes.ToList())
                {
                    _Context.DeleteObject(favoriteResume);
                }
                DeleteResume(resume);
                return 2;
            }
            else
            {
                if (resume.JobApplications.Count > 0)
                    return -2;
                else if (resume.FavoriteResumes.Count > 0)                    
                    return -3;

                DeleteResume(resume);
                return 1;
                
            }
        }

        /// <summary>
        /// Add a Resume file to the Lucene Index for Indexing
        /// </summary>
        /// <param name="resumeID"></param>
        /// <returns>
        /// -1 => Requested resume was not found for indexing
        /// -2 => Resume file was not found for indexing
        /// -3 => Permission denied. Probable hacking attempt
        /// +1 => Resume Indexed successfully
        /// </returns>
        [HttpPost]
        public String IndexResume(int resumeID)
        {
            Resume resume = _Context.Resumes.FirstOrDefault(P => P.ID == resumeID);
            if (resume == null)
                return new { Status = -1, SnapShot = String.Empty }.ToJSON();
            if (resume.JobSeekerID != LoggedInUser.JobSeekerID)
                return new { Status = -3, SnapShot = String.Empty }.ToJSON();

            String snapShot = resume.SnapShot;
            IIndexer resumeIndexer = IndexerFactory.GetIndexer(resume.GetType());
            resumeIndexer.UpdateIndex<Resume>(resume, "ResumeController.IndexResume");
            resumeIndexer.CommitChanges();
            resumeIndexer.CloseWriter();

            if (snapShot.IsNullOrEmpty() && !resume.SnapShot.IsNullOrEmpty())
                snapShot = resume.SnapShot;
            else
                snapShot = String.Empty;
                
            return new { Status = 1, SnapShot = snapShot }.ToJSON();
        }
		#endregion Action Methods
		
		#region Helper Methods
        /// <summary>
        /// Deletes Resume Index, Reloads Resume Searcher and removes the Resume file form file system.
        /// </summary>
        /// <param name="resume"></param>
        private void DeleteResume(Resume resume)
        {
            IIndexer indexer = IndexerFactory.GetIndexer(typeof(Resume));
            indexer.DeleteIndex(resume.ID);
            indexer.CommitChanges();
            indexer.CloseWriter();
            ///Reload Index Searcher
            ISearcher resumeSearcher = SearcherFactory.GetSearcher(typeof(Resume));
            resumeSearcher.Reload();

            String resumeFile = Path.Combine(Server.MapPath(AppConstants.Directories.RESUMES), resume.JobSeekerID.ToString(), resume.FileName);
            if (System.IO.File.Exists(resumeFile))
                System.IO.File.Delete(resumeFile);

            _Context.DeleteObject(resume);
            _Context.SaveChanges();
            JbEvents.ResumeDeleted(resume, _Context);
        }
        /// <summary>
        /// Builds ListConfig object for a Resume List of currently Logged in user
        /// </summary>
        /// <returns></returns>
        private ListConfig BuildResumeListConfig()
        {
            UtilityDAO dao = new UtilityDAO();
            Jb.Domain.DbParameter[] parameters = new[]{
                new Jb.Domain.DbParameter("@JobSeekerID", LoggedInUser.JobSeekerID)
            };
            DataSet ds = dao.GetDataSet(DbObject.SP.GET_RESUMES_BY_JOBSEEKER, parameters, true);
            PagerConfig pager = new PagerConfig(1, int.MaxValue, ds.Tables[0].Rows.Count);
            ListConfig listConfig = new ListConfig(ds.Tables[0], pager);
            ViewData[AppConstants.ViewDataKeys.SHOW_EDIT_LINK] = true;
            return listConfig;
        }

        /// <summary>
        /// Saves user uploaded resume to appropriate directory and deletes existing resume if exists, updates entity accordingly.
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="entity"></param>
        private void SaveResume(HttpPostedFileBase fileName, Resume entity)
        {
            String resumeDirectory = System.IO.Path.Combine(Server.MapPath(AppConstants.Directories.RESUMES), entity.JobSeekerID.ToString());

            if (fileName != null && fileName.ContentLength > 0)
            {
                if (!System.IO.Directory.Exists(resumeDirectory))
                    System.IO.Directory.CreateDirectory(resumeDirectory);

                ///Old File Exists Needs to be deleted at first
                if (!entity.FileName.IsNullOrEmpty() && String.Compare(entity.FileName, AppConstants.ValueOf.UNKNOWN) != 0)
                {
                    String existingResume = System.IO.Path.Combine(resumeDirectory, entity.FileName);
                    if (System.IO.File.Exists(existingResume))
                    {
                        System.IO.File.Delete(existingResume);
                    }
                }

                String proposedFileName = ImageManager.GetNextFileName(System.IO.Path.Combine(resumeDirectory, fileName.FileName));
                //proposedFileName = System.IO.Path.Combine(resumeDirectory, proposedFileName);
                fileName.SaveAs(System.IO.Path.Combine(resumeDirectory, proposedFileName));
                entity.FileName = proposedFileName;
            }
            else if (entity.FileName.IsNullOrEmpty())
                entity.FileName = AppConstants.ValueOf.UNKNOWN;

        }

        /// <summary>
        /// Makes all the default resume in active, Excluding the given Resume
        /// And removes any default resume from Lucene index
        /// </summary>
        /// <param name="excludeResumeID"></param>
        /// <param name="jobSeekerID"></param>
        private void RemoveResumeFromDefault(int excludeResumeID, int jobSeekerID)
        {
            List<Resume> resumes = (from P in _Context.Resumes where P.JobSeekerID == jobSeekerID && P.IsDefault && P.ID != excludeResumeID select P).ToList();
            if (resumes.Count > 0)
            {
                IIndexer resumeIndexer = IndexerFactory.GetIndexer(typeof(Resume));
                foreach (Resume resume in resumes)
                {
                    resumeIndexer.DeleteIndex(resume.ID);                    
                    resume.IsDefault = false;   
                }
                resumeIndexer.CommitChanges();
                resumeIndexer.CloseWriter();
                ISearcher resumeSearcher = SearcherFactory.GetSearcher(typeof(Resume));
                resumeSearcher.Reload();

                _Context.SaveChanges();
            }
        }
        #endregion			
    }
}


